/**
 *
 */
package com.honeybees.framework.mybatis.sqlsource;

import java.util.Map;

import org.apache.ibatis.builder.SqlSourceBuilder;
import org.apache.ibatis.builder.StaticSqlSource;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.SqlSource;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.apache.ibatis.scripting.xmltags.DynamicContext;
import org.apache.ibatis.scripting.xmltags.DynamicSqlSource;
import org.apache.ibatis.scripting.xmltags.SqlNode;
import org.apache.ibatis.session.Configuration;

/**
 * <dl>
 * <dt><b> 支持分页功能的动态SqlSource </b></dt>
 * <p>
 * <dd>功能描述</dd>
 * </dl>
 * <p>
 * Copyright (C) All rights reserved.
 * </p>
 *
 * @author 李远明
 * @since 2016年7月20日 下午8:26:49
 */
public class PageDynamicSqlSource extends AbstractPageSqlSource {

    private SqlNode rootSqlNode;

    public PageDynamicSqlSource(DynamicSqlSource sqlSource) {
        MetaObject metaObject = SystemMetaObject.forObject(sqlSource);
        this.configuration = (Configuration) metaObject.getValue("configuration");
        this.rootSqlNode = (SqlNode) metaObject.getValue("rootSqlNode");
    }

    /**
     * {@inheritDoc}
     *
     * @author 李远明
     * @version 2016年7月25日 上午10:09:57
     */
    @Override
    protected BoundSql getDefaultBoundSql(Object parameterObject) {
        DynamicContext context = new DynamicContext(configuration, parameterObject);
        rootSqlNode.apply(context);

        SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);
        Class<?> parameterType = parameterObject == null ? Object.class : parameterObject.getClass();
        SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings());
        sqlSource = new DefaultStaticSqlSource((StaticSqlSource) sqlSource);
        BoundSql boundSql = sqlSource.getBoundSql(parameterObject);

        // 设置条件参数
        for (Map.Entry<String, Object> entry : context.getBindings().entrySet()) {
            String name = entry.getKey();
            Object value = entry.getValue();
            boundSql.setAdditionalParameter(name, value);
        }
        return boundSql;
    }

    /**
     * {@inheritDoc}
     *
     * @author 李远明
     * @version 2016年7月20日 下午8:26:49
     */
    @Override
    protected BoundSql getCountBoundSql(Object parameterObject) {
        DynamicContext context = new DynamicContext(configuration, parameterObject);
        rootSqlNode.apply(context);

        SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);
        Class<?> parameterType = parameterObject == null ? Object.class : parameterObject.getClass();
        SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings());
        BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
        sqlSource = new StaticSqlSource(configuration, dialect.getCountSql(boundSql.getSql()),
                boundSql.getParameterMappings());
        boundSql = sqlSource.getBoundSql(parameterObject);

        // 设置条件参数
        for (Map.Entry<String, Object> entry : context.getBindings().entrySet()) {
            String name = entry.getKey();
            Object value = entry.getValue();
            boundSql.setAdditionalParameter(name, value);
        }
        return boundSql;
    }

    /**
     * {@inheritDoc}
     *
     * @author 李远明
     * @version 2016年7月20日 下午8:26:49
     */
    @Override
    protected BoundSql getPageBoundSql(Object parameterObject) {
        DynamicContext context = new DynamicContext(configuration, parameterObject);
        rootSqlNode.apply(context);

        SqlSourceBuilder sqlSourceParser = new SqlSourceBuilder(configuration);
        Class<?> parameterType = parameterObject == null ? Object.class : parameterObject.getClass();
        SqlSource sqlSource = sqlSourceParser.parse(context.getSql(), parameterType, context.getBindings());
        sqlSource = new DefaultStaticSqlSource((StaticSqlSource) sqlSource);
        BoundSql boundSql = sqlSource.getBoundSql(parameterObject);
        sqlSource = new StaticSqlSource(configuration, dialect.getPageSql(boundSql.getSql(), offset, limit),
                getPageParameterMapping(configuration, boundSql));
        boundSql = sqlSource.getBoundSql(parameterObject);

        // 设置条件参数
        for (Map.Entry<String, Object> entry : context.getBindings().entrySet()) {
            String name = entry.getKey();
            Object value = entry.getValue();
            boundSql.setAdditionalParameter(name, value);
        }
        return boundSql;
    }

}
